Spatial Data Visualisation in R

This blog post covers plotting spatial points and visualising spatial data on a map and in R. We will be covering the concepts of shapefiles, GeoJSON, Leaflets and sp objects and to how to read and manipulate them in R. At the end you would have created the following three interactive spatial maps:

  1. Pinpoint/Marker maps

  2. Heat maps

  3. Choropleth maps



Four steps to Spatial Data Visualisation

1. Read Shapefile or GeoJson as spatial or ‘sp’ objects in R 2. Read the crime data and process it as necessary 3. Convert the sp object into a Leaflet map widget 4. Mapping Spatial Data onto the map widget

Step 1: Reading Shapefile/GeoJson data as ‘sp’ objects

First let’s take a look at what shapefiles or GeoJson files and ‘sp’ objects actually are.

Shapefile and GeoJson Shapefile and GeoJson are file types storing the spatial data and associated geographical features. You can imagine them to be a dataframe with data stored as information of spatial distribution of points, lines and polygons lying in the the geographical region which that shapefile/GeoJson describes. Points in a Shapefile/GeoJson can represent points or geo-cordinates on a map, lines can represent rivers, roads etc and polygons can correspond to enclosed blocks of areas on a map. For example:

Screen Shot 2018-04-06 at 10.32.58 PM

Here, this shapefile has data stored in the form of spatial distribution of points ( indicating the wells), lines (denoting river) and polygon (denoting the lake here) in the region shown.

We would need a shapefile/geojson which would ultimately be converted into an sp object to map our spatial points on. Spatial (‘sp’) Objects sp is a package in R that provides classes and methods for dealing with spatial data. As discussed above, in spatial analysis, we crudely deal with the study of distribution of points, lines and polygons over a specific geographical region. ‘sp’ package can be considered to provide a class or a data type for storing such data. Thus an sp object is nothing but a variable of sp class.

Reading Shapefile/GeoJson into R and converting them into ‘sp’ or spatial object We would need Sh There are three easy ways to do this in R: 1. Reading GeoJson as sp object using ‘geojsonio’ from leaflet package 2. Reading Shapefile as sp object using ‘shapefile’ fucntion from raster package 3. Reading shapefile as sp object using ‘readOGR’ function from rgdal package.

Let’s load the required libraries first.

library(rgdal)#   1required for readOGR fucntion
library(raster)# 2required for shapefile function
library(leaflet)   # 3 reading geojson

#library(dplyr)     # required for as_tibble function
library(leaflet.extras) # required for generating heatmaps

The link for the required shapefiles/geojson is LINK

All the three maps read above would be of class ‘sp’. Let’s verify it once.

# Class types of all the three maps is 'sp'
class(assam_map)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"
class(assam_map1)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"
class(assam_map2)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"

Also notice that all these three objects are SpatialPolygonDataFrame. That’s because these maps contain information on distribution on polygons, which denote districts in Assam in our demo. We will use ‘assam_map’ for our demo, though, any of the three would work fine. Let’s explore this ‘sp’ object assam_map further

library(ggplot2)
plot(assam_map)

library(dplyr) # For as_tibble function
as_tibble(assam_map)
## # A tibble: 27 x 5
##    DISTRICT   DT_CEN_CD ST_CEN_CD ST_NM censuscode
##  * <fct>          <int>     <int> <fct>      <int>
##  1 Baksa             25        18 Assam        324
##  2 Barpeta            4        18 Assam        303
##  3 Bongaigaon        20        18 Assam        319
##  4 Cachar            17        18 Assam        316
##  5 Chirang           21        18 Assam        320
##  6 Darrang           26        18 Assam        325
##  7 Dhemaji            9        18 Assam        308
##  8 Dhubri             2        18 Assam        301
##  9 Dibrugarh         11        18 Assam        310
## 10 Goalpara           3        18 Assam        302
## # ... with 17 more rows

Step 2: Loading the spatial data

The data I would be using for this demo is synthetic. It’s the same data I had used for the Satark Analytics Web App. You can find the csv file here LINKKKKK

#Load in your crime data
crimeData<-read.csv("assamcrimedata.csv")
crimeDemo<-crimeData[1:10,]
#Get an ovrview of crimeDemo
as_tibble(crimeDemo)
## # A tibble: 10 x 7
##    dates   crimetype     lat   lng crimedistricts victim_age victim_gender
##  * <fct>   <fct>       <dbl> <dbl> <fct>               <int> <fct>        
##  1 2017-0~ Other theft  26.8  93.5 Sonitpur               15 M            
##  2 2017-0~ Other theft  26.5  91.6 Kamrup                  5 M            
##  3 2017-0~ Drugs        26.2  91.3 Kamrup                 NA ""           
##  4 2017-0~ Shoplifting  26.6  93.4 Golaghat               NA ""           
##  5 2017-0~ Shoplifting  26.6  92.0 Udalguri               NA ""           
##  6 2017-0~ Anti-socia~  26.5  90.5 Chirang                NA ""           
##  7 2017-0~ Other theft  26.1  93.9 Golaghat               21 F            
##  8 2017-0~ Bicycle th~  26.9  94.0 Lakhimpur               7 F            
##  9 2017-0~ Other theft  26.1  90.6 Goalpara               19 F            
## 10 2017-0~ Other theft  26.2  91.5 Kamrup                 47 M

Step 3: Converting the ‘sp’ object generated above into a Leaflet Map Widget

Leaflet is a JavaScript library to create interactive maps. Find more details here Leaflet for R.

The ‘leaflet()’ function generates a map widget, which stores a list of objects. It mostly takes a map as an input, but can also take data frames or matrices having latitude and longitude as inputs.

For our purpose we would be giving a SpatialPolygonDataFrame (assam_map) as input. The map widget generated then could be considered as the final map which is ready to be plotted.

assam_leaflet<-leaflet(assam_map) %>% addPolygons()
assam_leaflet

This is the Assam leaflet we obtain. Let’s make it a little better looking.

assam_leaflet<-leaflet(assam_map) %>% addPolygons(color="#444444",weight=1) 

assam_leaflet

Thus our leaflet is ready to be mapped upon. It’s time to move onto the last step.

Step 4: Mapping Spatial Data onto the map widget

Pinpoint or Marker plotting We will be marking up the crime points from our crimeDemo dataset onto the leaflet we have generated in the last step. We will be using the addMarkers function for the same.

assamMarker<-assam_leaflet %>% 
      addMarkers(data = crimeDemo,~lng, ~lat)
assamMarker

Let’s further add the functionality of generating a popup table when these markers are being clicked.

library(mapview) # for generating popupTable
assamMarker<-assam_leaflet %>% 
      addMarkers(data = crimeDemo,~lng, ~lat,popup= popupTable(crimeDemo))
assamMarker

Heatmap

library(leaflet.extras) # required for addHeatmap function
assamHeatmap<-assam_leaflet %>%
        addHeatmap(data= crimeDemo,lng=~lng, lat=~lat,
                   blur = 20, max = 0.05, radius = 15 ) 
      
assamHeatmap

Choropleth

Generating chorpleth can be tricky. I would strongly urge you to checkout the documentation page for leaflet choropleth

Firstly, we need to process the crimeData (we won’t be using crimeDemo here because it contains to few a points for proper demonstration of a chorpleth). We need to build a count table which contains the district and the count of crimes taking place against every district. This can be easily done using the ‘count()’ function in R.

districtCrimeCount<-count(crimeData,vars=crimedistricts)
head(districtCrimeCount)
## # A tibble: 6 x 2
##   vars           n
##   <fct>      <int>
## 1 Baksa         16
## 2 Barpeta       15
## 3 Bongaigaon     6
## 4 Chirang       12
## 5 Darrang        8
## 6 Dhubri         7

Next, we generate three utility containers as foloows: bins : will help us to generate the color palette. Each bin interval will be assigned a different color in the palette. pal : to decide the color-coding scheme with respect to the number of crimes labels : to generate the interactive labels that appear on hovering over the map

bins <- c(0,3,6,9, 12, 15, 18, 21, 24,27,30,Inf)

pal <- colorBin("YlOrRd", domain = districtCrimeCount$n, bins = bins)

labels <- sprintf(
        "<strong>%s</strong><br/>%g Crimes ",
        districtCrimeCount$vars, districtCrimeCount$n
      ) %>% lapply(htmltools::HTML)

Next, we generate the choropleth by manipulating the addPolygons() function as follows

assam_choropleth<-assam_leaflet %>% addPolygons(
  fillColor = ~pal(districtCrimeCount$n),
  weight = 2,
  opacity = 1,
  dashArray = "3",
  color = "white",
  fillOpacity = 0.7,
  highlight = highlightOptions(
    weight = 5,
    color = "#666",
    bringToFront = TRUE),
  label = labels) %>% 
  addLegend(pal = pal, values = ~n, opacity = 0.7, title = NULL,
            position = "bottomright")

assam_choropleth